package com.un.ebs.core.util;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.ObjectListing;
import com.un.ebs.core.config.OSSConfig;
import com.un.ebs.core.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Component
public class OSSUtil {


    private static OSSConfig config;
    /**
     * oss 工具客户端
     */
    private volatile static OSSClient ossClient = null;

    private static final Logger logger = LoggerFactory.getLogger(OSSUtil.class);

    @Resource
    private OSSConfig ossConfig;

    public static String getPath(String objectType, String objectId, String resourceType) {
        return String.format("%s/%s/%s", objectType, objectId, resourceType);
    }

    /**
     * 上传文件至阿里云 OSS
     * 文件上传成功,返回文件完整访问路径
     * 文件上传失败,返回 null
     *
     * @param file    待上传文件
     * @param fileDir 文件保存目录
     * @return oss 中的相对文件路径
     */
    public static String upload(MultipartFile file, String fileDir) {
        StringBuilder fileUrl = new StringBuilder();
        try {
            System.out.println();
            System.out.println(file.getOriginalFilename());
            System.out.println();
            String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
            String fileName = System.currentTimeMillis() + "-" + UUID.randomUUID().toString().substring(0, 18) + suffix;
            if (!fileDir.endsWith("/")) {
                fileDir = fileDir.concat("/");
            }
            fileUrl = fileUrl.append(fileDir + fileName);
            ossClient.putObject(config.getBucketName(), fileUrl.toString(), file.getInputStream());
        } catch (IOException e) {
            logger.error("上传文件失败:" + fileDir + ", " + e.getMessage());
            throw new BusinessException(e.getMessage());
        }

        return fileUrl.toString();
    }

    public static String upload(MultipartFile file, String fileDir, String fileName) {
        StringBuilder fileUrl = new StringBuilder();
        try {
            String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
            if (StringUtils.isNullOrEmpty(fileName)) {
                fileName = System.currentTimeMillis() + "-" + UUID.randomUUID().toString().substring(0, 18) + suffix;
            } else {
                fileName = fileName + suffix;
            }
            if (!fileDir.endsWith("/")) {
                fileDir = fileDir.concat("/");
            }
            fileUrl = fileUrl.append(fileDir + fileName);
            ossClient.putObject(config.getBucketName(), fileUrl.toString(), file.getInputStream());
        } catch (IOException e) {
            logger.error("上传文件失败:" + fileDir + ", " + e.getMessage());
            throw new BusinessException(e.getMessage());
        }

        return fileUrl.toString();
    }

    public static String upload(MultipartFile file, String fileDir, String fileName, String key) {
        StringBuilder fileUrl = new StringBuilder();
        try {
            String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
            if (StringUtils.isNullOrEmpty(fileName)) {
                fileName = System.currentTimeMillis() + "-" + UUID.randomUUID().toString().substring(0, 18) + suffix;
            } else {
                fileName = fileName + suffix;
            }
            if (!fileDir.endsWith("/")) {
                fileDir = fileDir.concat("/");
            }
            fileUrl = fileUrl.append(fileDir + fileName);
            ossClient.putObject(config.getBucketName(), key, file.getInputStream());
        } catch (IOException e) {
            logger.error("上传文件失败:" + fileDir + ", " + e.getMessage());
            throw new BusinessException(e.getMessage());
        }

        return fileUrl.toString();
    }

    public static String upload(String sourceUrl, String fileDir, String extName) {
        if (StringUtils.isNullOrEmpty(sourceUrl) || StringUtils.isNullOrEmpty(fileDir)) {
            logger.error("上传时，指定的源文件地址为空：" + sourceUrl);
            return null;
        }

        StringBuilder fileUrl = new StringBuilder();
        try {

            String fileName = System.currentTimeMillis() + "-" + UUID.randomUUID().toString().substring(0, 18);
            fileUrl = fileUrl.append(fileDir + "/" + fileName);
            if (!StringUtils.isNullOrEmpty(extName)) {
                fileUrl.append(extName);
            }

            URL url = new URL(sourceUrl);
            DataInputStream inputStream = new DataInputStream(url.openStream());
            ossClient.putObject(config.getBucketName(), fileUrl.toString(), inputStream);
            return fileUrl.toString();
        } catch (MalformedURLException e) {
            logger.error("上传URL失败:" + sourceUrl + ", " + e.getMessage());
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        } catch (IOException e) {
            logger.error("上传URL时，失败:" + sourceUrl + ", " + e.getMessage());
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }

    public static List<String> batchUpload(List<MultipartFile> files, String fileDir) {
        List<String> result = new ArrayList<>();
        for (MultipartFile file : files) {
            String keyResult = OSSUtil.upload(file, fileDir);
            result.add(keyResult);
        }
        return result;
    }

    public static ObjectListing list(String prefix) {
        return ossClient.listObjects(config.getBucketName(), prefix);
    }

    public static List<String> listKey(String prefix) {
        return ossClient.listObjects(config.getBucketName(), prefix).getObjectSummaries().stream().map(s -> s.getKey()).collect(Collectors.toList());
    }

    public static void delete(String key) {
        if (ossClient.doesObjectExist(config.getBucketName(), key)) {
            ossClient.deleteObject(config.getBucketName(), key);
        }
    }

    public static URL getObjectUrl(String key) {
        return ossClient.generatePresignedUrl(config.getBucketName(), key, DateUtils.plusDay(1), HttpMethod.GET);
    }

    public static URL getObjectUrl(String key, String styleName) {
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(config.getBucketName(), key, HttpMethod.GET);
        req.setExpiration(DateUtils.plusDay(1));
        req.setProcess("style/" + styleName);
        return ossClient.generatePresignedUrl(req);
    }

    /**
     * 初始化 oss 客户端
     *
     * @param config
     * @return
     */
    private static OSSClient initOss(OSSConfig config) {
        if (config == null) {
            return null;
        }
        if (StringUtils.isNullOrEmpty(config.getAccessKeyId()) || StringUtils.isNullOrEmpty(config.getAccessKeySecret())) {
            return null;
        }

        if (ossClient == null) {
            synchronized (OSSUtil.class) {
                if (ossClient == null) {
                    ossClient = new OSSClient(config.getEndpoint(),
                            new DefaultCredentialProvider(config.getAccessKeyId(), config.getAccessKeySecret()),
                            new ClientConfiguration());
                }
            }
        }
        return ossClient;
    }

    @PostConstruct
    private void init() {
        config = ossConfig;
        initOss(config);
    }
}
